/**
 * @description Online，基于浏览器环境，提供弱网检测能力。
 * 在实例化时可配置正常网络、弱网、断网时的回调处理函数
 * @example
 * import Online from './Online'
 * const NW = new Online({
 *      //正常网络
 *      online: ()=>{ ... },
 *      //弱网
 *      lowline: ()=>{ ... },
 *      //断网
 *      offline: ()=>{ ... }
 * })
 * ...
 * 甚至，还可以在实例化后，单独设置回调或其他参数，例如：
 * 设置弱网上限值（默认400）
 * NW.defaults.rtt = 100;
 * NW.defaults.lowline = function(){console.log("新设置的弱网回调函数")};
 * ...
 */
class Online{
  
    constructor(config) {
        this.defaultConfig = {
            //网络正常执行函数
            online: function () {},
            //弱网执行函数
            lowline: function () {},
            //网络异常执行函数
            offline: function () {},
            //睡眠执行函数
            onsleep: function () { },
            //错误回调
            onerror: function () { },
            //最小睡眠时间段(ms)
            sleepTime: 10000,
            //网络状态检测间隔时间(ms)
            lineTime: 10000,
            //检测睡眠定时器时间(ms)
            sleepInterval: 3000,
            //估算，弱网的往返时间阀值(单位：ms)
            rtt: 400,
            //网络下行速度，弱网网速阀值（MB/s）
            downlink: 1
        }
        this.onLineInfoTimeout = null;
        this.config = Object.assign(this.defaultConfig, config || {});
        this._onLineChange();

        const self = this;
        this.defaults = new Proxy({}, {
            get(target, attr) {
                return self.config[attr]
            },
            set(target, attr, value) {
                self.config[attr] = value
                if(navigator.connection) self._onLineInfo();
            }
        })
    }

    _onLineChange() {
        //针对离线应用的缓存，再次打开时的首次检测。
        if (!navigator.onLine) this.config.offline();
        //有网的情况下，进行一次弱网检测。
        else if(navigator.connection) this._onLineInfo();

        window.addEventListener("online", () => {

            this.config.online();
            this._onLineInfo();
            
        }, false);

        window.addEventListener("offline", () => {

            this.config.offline();

            clearTimeout(this.onLineInfoTimeout);
            this.onLineInfoTimeout = null

        }, false);

        //设备睡眠监测
        this._onSleep();
    }

    _onLineInfo() {
        if (navigator.connection) {
            const { rtt, downlink } = navigator.connection;
            if (rtt > this.config.rtt || downlink < this.config.downlink) {
                this.config.lowline();
            }

            clearTimeout(this.onLineInfoTimeout);
            this.onLineInfoTimeout = null;
            this.onLineInfoTimeout = setTimeout(() => {
                this._onLineInfo();
            }, this.config.lineTime);
        }
        else {
            const msg = '网络监测：当前浏览器暂不支持网络状态的监测.'
            console.warn(msg)
            this.config.onerror && this.config.onerror(msg)
        }

    }

    _onSleep() {
        let time = new Date().getTime();
        setInterval(() => {
            let _t = new Date().getTime();
            if (_t - time > this.config.sleepTime) {
                this.config.onsleep();
                this.config.offline();
                if (navigator.onLine) {
                    this.config.online();
                    time = _t;
                }
            } else {
                time = _t;
            }
        }, this.config.sleepInterval)
    }
}

export default Online